import pandas as pd
import numpy as np
import logging
from datetime import datetime

logging.basicConfig(level=logging.INFO)

def evaluate_sequential_results(csv_paths, thresholds):
    """
    按顺序评估算法组合效果
    csv_paths: 有序字典，按使用顺序排列的算法结果文件路径
    thresholds: 字典，每个算法对应的阈值
    """
    # 加载所有结果
    results = {}
    for provider, path in csv_paths.items():
        results[provider] = pd.read_csv(path)
    
    # 获取所有图片
    all_images = set()
    for df in results.values():
        all_images.update(df['image_name'])
    
    # 记录每张图片的最终判定结果
    final_decisions = []  # 这个变量名也可以改为 liveness_results
    
    # 按顺序处理每张图片
    for img in all_images:
        used_algorithm = None      # 最终使用的算法
        final_score = None        # 最终使用的分数
        
        # 按指定顺序尝试每个算法（顺序由csv_paths的键顺序决定）
        for provider in csv_paths.keys():
            # 获取当前算法的结果数据
            df = results[provider]
            # 查找当前图片在该算法结果中的记录
            img_result = df[df['image_name'] == img]
            
            # 如果找到该图片的检测结果
            if not img_result.empty:
                # 获取该算法对这张图片的评分
                score = img_result.iloc[0]['score']
                
                # 如果分数达到或超过该算法的阈值，或者这是最后一个算法
                if score >= thresholds[provider] or provider == list(csv_paths.keys())[-1]:
                    used_algorithm = provider     # 记录使用的算法
                    final_score = score          # 记录最终分数
                    break                       # 找到合适的算法后立即退出循环
        
        # 获取图片的原始类型
        img_result = next(df[df['image_name'] == img].iloc[0] for df in results.values())
        
        # 将该图片的处理结果添加到最终结果列表
        final_decisions.append({
            'image_name': img,                    # 图片名称
            'type': img_result['type'],          # 图片真实类型（real/fake）
            'final_score': final_score,          # 最终使用的分数
            'used_algorithm': used_algorithm,     # 使用的算法
            'pass_liveness_check': final_score >= thresholds[used_algorithm]  # 是否通过活体检测
        })
    
    # 转换为DataFrame
    liveness_results_df = pd.DataFrame(final_decisions)
    
    # 计算指标
    # True Positive：真实为真人（real）且通过活体检测的数量
    tp = sum((liveness_results_df['type'] == 'real') & liveness_results_df['pass_liveness_check'])

    # False Negative：真实为真人（real）但未通过活体检测的数量
    fn = sum((liveness_results_df['type'] == 'real') & ~liveness_results_df['pass_liveness_check'])

    # False Positive：真实为假人（fake）但错误通过活体检测的数量
    fp = sum((liveness_results_df['type'] == 'fake') & liveness_results_df['pass_liveness_check'])

    # True Negative：真实为假人（fake）且正确未通过活体检测的数量
    tn = sum((liveness_results_df['type'] == 'fake') & ~liveness_results_df['pass_liveness_check'])
    
    total_real = tp + fn
    total_fake = fp + tn
    
    recall = tp / total_real if total_real > 0 else 0
    frr = fn / total_real if total_real > 0 else 0
    far = fp / total_fake if total_fake > 0 else 0
    hter = (far + frr) / 2
    
    # 输出结果
    logging.info("\n序列组合结果:")
    logging.info(f"使用顺序: {' -> '.join(csv_paths.keys())}")
    logging.info(f"各算法阈值: {thresholds}")
    logging.info(f"TP (真脸被正确识别为真脸): {tp}")
    logging.info(f"TN (假脸被正确识别为假脸): {tn}")
    logging.info(f"FP (假脸被错误识别为真脸): {fp}")
    logging.info(f"FN (真脸被错误识别为假脸): {fn}")
    logging.info(f"召回率: {recall:.3%}")
    logging.info(f"FRR: {frr:.3%}")
    logging.info(f"FAR: {far:.3%}")
    logging.info(f"HTER: {hter:.3%}")
    
    # 计算每个算法的使用情况
    algorithm_usage = liveness_results_df['used_algorithm'].value_counts()
    logging.info("\n各算法使用统计:")
    for alg, count in algorithm_usage.items():
        logging.info(f"算法 {alg}: {count}次 ({count/len(liveness_results_df):.1%})")
    
    # 保存详细结果
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    liveness_results_df.to_csv(f'sequential_results_{timestamp}.csv', index=False, encoding='utf-8-sig')
    
    return liveness_results_df

if __name__ == "__main__":
    # 按使用顺序指定算法结果文件路径
    csv_paths = {
        '3': r'D:\Project\livenessDetect\provider3\全部照片的活体检测结果20241227_002732.csv',
        '1': r'D:\Project\livenessDetect\provider1\全部照片的活体检测结果20241226_221629.csv',
        '2': r'D:\Project\livenessDetect\provider2\全部照片的活体检测结果20241227_101828.csv'
    }
    
    # 指定每个算法的阈值
    thresholds = {
        '3': 0,  # 算法3的阈值
        '1': 0.7,  # 算法1的阈值
        '2': 0.5   # 算法2的阈值
    }
    
    # 评估序列组合效果
    evaluate_sequential_results(csv_paths, thresholds) 